home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / pr.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  12KB  |  511 lines

  1. /* pr - print files            Author: Michiel Huisjes */
  2.  
  3.  
  4. /* Pr - print files
  5.  *
  6.  * Author: Michiel Huisjes.
  7.  * Modified: Jacob P. Bunschoten.    (30 nov 87)
  8.  *    When "columns" is not given and numbering is on:
  9.  *        line numbers are correlated with input lines.
  10.  *    (try pr [-1] -n file )
  11.  *    tabs are accounted for.
  12.  *    When numbering is turned on, width know this.
  13.  *    automatic line-folding. -f to get the original program.
  14.  *    backspaces are accounted for. -b to disable this.
  15.  *    multi-column mode changed.
  16.  *    header can be given and used.
  17.  *    format changed may occur between printing of several files:
  18.  *        pr -l30 file1 -w75 file2
  19.  *
  20.  * Modified: Rick Thomas.        (Sept 12, 1988)
  21.  *    added "-M" option to cover functionality of old "-n" option,
  22.  *    and made "-n" option behavior compatible with system V.
  23.  *
  24.  * Usage: pr [+page] [-columns] [-h header] [-wwidth] [-llength] [-ntm] [files]
  25.  *        -t : Do not print the 5 line header and trailer at the page.
  26.  *        -n : Turn on line numbering.
  27.  *        -M : Use "Minix" style line numbering -- Each page begins at
  28.  *             a line number that is an even multiple of the page length.
  29.  *             Like the listings in Appendix E of the book.
  30.  *        +page    : Start printing at page n.
  31.  *        -columns : Print files in n-columns.
  32.  *        -l length: Take the length of the page to be n instead of 66
  33.  *        -h header: Take next argument as page header.
  34.  *        -w width  : Take the width of the page to be n instead of default 79
  35.  *      -f : do not fold lines.
  36.  * Modified: Lars Fredriksen        (Jan 19, 1990)
  37.  *    fixed the program so that 
  38.  *        pr -n *.c
  39.  *    would work. The clobal variable 'width' was decremented
  40.  *    by NUM_WIDTH, for each file, resulting in width finally
  41.  *    being so small that nothing was printed. Used the local
  42.  *    variable 'w' for the width adjustment (in print())
  43.  */
  44.  
  45. #include <stdio.h>
  46.  
  47. #define DEF_LENGTH    66
  48. #define DEF_WIDTH    79
  49. #define NUM_WIDTH    8
  50. #define TAB_WIDTH    8    /* fixed tab_width */
  51.  
  52. /* Used to compute next (fixed) tabstop */
  53. #define TO_TAB(x)    (( (x) + TAB_WIDTH ) & ~07 )
  54.  
  55. typedef char BOOL;
  56.  
  57. #define FALSE        0
  58. #define TRUE        1
  59.  
  60. #define NIL_PTR        ((char *) 0)
  61.  
  62. /* EAT:    eat rest of input line */
  63. #define EAT(fp)        while((c=getc(fp))!='\n' && c!=EOF)
  64.  
  65. /* L_BUF: calculate address of pointer to char (string) used in format */
  66. #define L_BUF(i,j)    * (char **) (line_buf + (i + j*length)*sizeof(char *))
  67.  
  68. char *header;
  69. BOOL no_header;
  70. BOOL number = FALSE;
  71. BOOL minix_number = FALSE;
  72. BOOL ext_header_set = FALSE;    /* external header given */
  73. BOOL back_space = TRUE;        /* back space correction in line width */
  74. BOOL dont_fold = FALSE;        /* original. If the line does not fit eat it.*/
  75. short columns;
  76. short cwidth;
  77. short start_page = 1;
  78. short width = DEF_WIDTH;
  79. short length = DEF_LENGTH;
  80. short linenr;
  81. char *line_buf;            /* used in format for multi-column output */
  82.  
  83. char output[1024];
  84. FILE *fopen();
  85. static char *myalloc();
  86.  
  87. main(argc, argv)
  88. int argc;
  89. char *argv[];
  90. {
  91.   FILE *file;
  92.   char *ptr;
  93.   int index = 1;        /* index is one ahead of argc */
  94.   int line, col;
  95.  
  96.   setbuf(stdout, output);
  97.   do {
  98.     if (argc == index)    /* No arguments (left) */
  99.         goto pr_files;
  100.  
  101.     ptr = argv[index++];
  102.     if (*ptr == '+') {
  103.         start_page = atoi(++ptr);
  104.         continue;
  105.     }
  106.     if (*ptr != '-') {    /* no flags */
  107.         index--;
  108.         goto pr_files;
  109.     }
  110.     if (*++ptr >= '0' && *ptr <= '9') {
  111.         columns = atoi(ptr);
  112.         if (columns <= 0) columns = 1;
  113.         continue;    /* Fetch next flag */
  114.     }
  115.     while (*ptr) switch (*ptr++) {
  116.             case 't':    no_header = TRUE;    break;
  117.             case 'n':
  118.             number = TRUE;
  119.             minix_number = FALSE;
  120.             break;
  121.             case 'M':
  122.             number = TRUE;
  123.             minix_number = TRUE;
  124.             break;
  125.             case 'h':
  126.             header = argv[index++];
  127.             ext_header_set = TRUE;
  128.             break;
  129.             case 'w':
  130.             if ((width = atoi(ptr)) <= 0) width = DEF_WIDTH;
  131.             *ptr = '\0';
  132.             break;
  133.             case 'l':
  134.             if ((length = atoi(ptr)) <= 0) length = DEF_LENGTH;
  135.             *ptr = '\0';
  136.             break;
  137.             case 'b':    /* back_space correction off */
  138.             back_space = FALSE;
  139.             break;
  140.             case 'f':    /* do not fold lines */
  141.             dont_fold = TRUE;
  142.             break;
  143.             default:
  144.             fprintf(stderr, "Usage: %s [+page] [-columns] [-h header] [-w<width>] [-l<length>] [-nMt] [files]\n", argv[0]);
  145.             exit(1);
  146.         }
  147.     continue;        /* Scan for next flags */
  148.  
  149.  
  150.     /* ==============  flags are read. Print the file(s) ========= */
  151.  
  152. pr_files:
  153.  
  154.     if (!no_header) length -= 10;
  155.  
  156.     if (columns) {
  157.         cwidth = width / columns + 1;
  158.         if (columns > width) {
  159.             fprintf(stderr, "Too many columns for page width.\n");
  160.             exit(1);
  161.         }
  162.  
  163.         /* Allocate piece of mem to hold some pointers */
  164.         line_buf = myalloc(length * columns * sizeof(char *));
  165.     }
  166.     for (line = 0; line < length; line++)
  167.         for (col = 0; col < columns; col++)
  168.             L_BUF(line, col) = NIL_PTR;
  169.  
  170.     if (length <= 0) {
  171.         fprintf(stderr, "Minimal length should be %d\n", no_header ?
  172.             1 : 11);
  173.         exit(1);
  174.     }
  175.     while (index <= argc) {    /* print all files, including stdin */
  176.         if (index < argc && (*argv[index] == '-' || *argv[index] == '+'))
  177.             break;    /* Format change */
  178.  
  179.         if (argc == index) {    /* no file specified, so stdin */
  180.             if (!ext_header_set) header = "";
  181.             file = stdin;
  182.         } else {
  183.             if ((file = fopen(argv[index], "r")) == (FILE *) 0) {
  184.                 fprintf(stderr, "Cannot open %s\n", argv[index++]);
  185.                 continue;
  186.             }
  187.             if (!ext_header_set) header = argv[index];
  188.         }
  189.         if (columns)
  190.             format(file);
  191.         else
  192.             print(file);
  193.         fclose(file);
  194.         if (++index >= argc)
  195.             break;    /* all files (including stdin) done */
  196.     }
  197.     if (index >= argc) break;
  198.     /* When control comes here. format changes are to be done.
  199.      * reinitialize some variables */
  200.     if (!no_header) length += 10;
  201.  
  202.     start_page = 1;
  203.     ext_header_set = FALSE;
  204.     if (columns) free(line_buf);
  205.   } while (index <= argc);    /* "pr -l60" should work too */
  206.  
  207.   (void) fflush(stdout);
  208.   exit(0);
  209. }
  210.  
  211. char skip_page(lines, width, filep)
  212. int lines, width;
  213. FILE *filep;
  214. {
  215.   short c;
  216.   int char_cnt;
  217.   int w;
  218.  
  219.   do {
  220.     w = width;
  221.     if (number)        /* first lines are shorter */
  222.         if (!columns ||    /* called from print(file)  */
  223.             !(lines % columns))    /* called from format(file) */
  224.             w -= NUM_WIDTH;
  225.  
  226.     char_cnt = 0;
  227.     while ((c = getc(filep)) != '\n' && c != EOF && char_cnt < w) {
  228.         /* Calculate if this line is longer than "width (w)"
  229.          * characters */
  230.         if (c == '\b' && back_space) {
  231.             if (--char_cnt < 0) char_cnt = 0;
  232.         } else if (c == '\t')
  233.             char_cnt = TO_TAB(char_cnt);
  234.         else
  235.             char_cnt++;
  236.     }
  237.     if (dont_fold && c != '\n' && c != EOF) EAT(filep);
  238.     lines--;
  239.     if (c == '\n') linenr++;
  240.   } while (lines > 0 && c != EOF);
  241.  
  242.   return c;            /* last char read */
  243. }
  244.  
  245. format(filep)
  246. FILE *filep;
  247. {
  248.   char buf[512];
  249.   short c = '\0';
  250.   short index, lines, i;
  251.   short page_number = 0;
  252.   short maxcol = columns;
  253.   short wdth;
  254.   short line, col;
  255.  
  256.   do {
  257.     /* Check printing of page */
  258.     page_number++;
  259.  
  260.     if (page_number < start_page && c != EOF) {
  261.         c = (char) skip_page(columns * length, cwidth, filep);
  262.         continue;
  263.     }
  264.     if (c == EOF) return;
  265.  
  266.     lines = columns * length;
  267.     for (line = 0; line < length; line++)
  268.         for (col = 0; col < columns; col++) {
  269.             if (L_BUF(line, col) != NIL_PTR)
  270.                 free(L_BUF(line, col));
  271.             L_BUF(line, col) = (char *) NIL_PTR;
  272.         }
  273.     line = 0;
  274.     col = 0;
  275.     do {
  276.         index = 0;
  277.         wdth = cwidth - 1;
  278.         if (number && !col)    /* need room for numbers */
  279.             wdth -= NUM_WIDTH;
  280.  
  281.         /* Intermidiate colums are shortened by 1 char */
  282.         /* Last column not */
  283.         if (col + 1 == columns) wdth++;
  284.         for (i = 0; i < wdth - 1; i++) {
  285.             c = getc(filep);
  286.             if (c == '\n' || c == EOF) break;
  287.  
  288.             if (c == '\b' && back_space) {
  289.                 buf[index++] = '\b';
  290.                 if (--i < 0) {    /* just in case ... */
  291.                     i = 0;
  292.                     index = 0;
  293.                 }
  294.             } else if (c == '\t') {
  295.                 int cnt, max;
  296.  
  297.                 max = TO_TAB(i);
  298.                 for (cnt = i; cnt < max; cnt++)
  299.                     buf[index++] = ' ';
  300.                 i = max - 1;
  301.             } else
  302.                 buf[index++] = (char) c;
  303.         }
  304.         buf[index++] = '\0';
  305.         /* Collected enough chars (or eoln, or EOF) */
  306.  
  307.         /* First char is EOF */
  308.         if (i == 0 && lines == columns * length && c == EOF) return;
  309.  
  310.         /* Alloc mem to hold this (sub) string */
  311.         L_BUF(line, col) = myalloc(index * sizeof(char));
  312.         strcpy(L_BUF(line, col), buf);
  313.  
  314.         line++;
  315.         line %= length;
  316.         if (line == 0) {
  317.             col++;
  318.             col %= columns;
  319.         }
  320.         if (dont_fold && c != '\n' && c != EOF) EAT(filep);
  321.         l